//---------------------------------------------------------------------------
#include "stdafx.h"
//---------------------------------------------------------------------------
#include "shader.h"


const char* ShaderSource::getSource() {
	return m_source; 
}


bool validateShader(GLuint shader) {

	int length;
	glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);

	if (length > 1) {
		char* log = new char[length];

		glGetShaderInfoLog(shader, length, NULL, (GLchar*) log);

		output << log;

		delete[] log;
	}
	return shader != 0;
}

VertexShader& VertexShader::operator= (const VertexShader& other) {
	m_shader = other;

	return *this;
}

FragmentShader& FragmentShader::operator= (const FragmentShader& other) {
	m_shader = other;

	return *this;
}

void FragmentShader::compile(const char* source_ptr) {
	m_shader = glCreateShader(GL_FRAGMENT_SHADER);

	glShaderSource(m_shader, 1, &source_ptr, NULL);
	glCompileShader(m_shader);
	validateShader(m_shader);
}


void VertexShader::compile(const char* source_ptr) {
	m_shader = glCreateShader(GL_VERTEX_SHADER);

	glShaderSource(m_shader, 1, &source_ptr, NULL);
	glCompileShader(m_shader);
	validateShader(m_shader);
}

void Shader::compile(uint32 num_attributes, attribute* attributes) {
	m_num_attributes = num_attributes;
	m_attributes = attributes;

	m_program = glCreateProgram();

	for (uint32 i = 0; i < m_num_attributes; i++) {
		attribute& attr = m_attributes[i];
		glBindAttribLocation(m_program, attr.id, attr.name);
	}

	glAttachShader(m_program, m_vertex_shader);

	glAttachShader(m_program, m_fragment_shader);

	glLinkProgram(m_program);

	//ReportGLErrors();
}

void Shader::bind() {
	glUseProgram(m_program);
}

GLint Shader::getUniformLocation(const char* var) {
	return glGetUniformLocation(m_program, var);
}

void Shader::setSampler(GLint var, uint32 unit) {
	glUniform1i(var, (int)unit);
}

void Shader::setSamplers(GLint var, uint32 count, const uint32* units) {
	glUniform1iv(var, count, (const GLint*)units);
}

void Shader::setFloat(GLint var, GLfloat v) {
	glUniform1f(var, v);
}

void Shader::setInteger(GLint var, GLint v) {
	glUniform1i(var, v);
}

void Shader::setUInteger(GLint var, GLuint v) {
	glUniform1ui(var, v);
}

void Shader::setUIntegerArray(GLint var, GLuint* v, uint32 N) {
	glUniform1uiv(var, N, v);
}

void Shader::setVector2i(GLint var, int x, int y) {
	glUniform2i(var, x, y);
}

void Shader::setVector2f(GLint var, GLfloat x, GLfloat y) {
	glUniform2f(var, x, y);
}

void Shader::setVector3f(GLint var, GLfloat x, GLfloat y, GLfloat z) {
	glUniform3f(var, x, y, z);
}

void Shader::setVector4i(GLint var, int x, int y, int z, int w) {
	glUniform4i(var, x, y, z, w);
}

void Shader::setVector4f(GLint var, Vector4d v) {
	glUniform4f(var, (GLfloat)v[0], (GLfloat)v[1], (GLfloat)v[2], (GLfloat)v[3]);
}

void Shader::setVector4f(GLint var, Vector4f v) {
	glUniform4f(var, (GLfloat)v[0], (GLfloat)v[1], (GLfloat)v[2], (GLfloat)v[3]);
}

void Shader::setVector4f(GLint var, GLfloat x, GLfloat y, GLfloat z, GLfloat w) {
	glUniform4f(var, x, y, z, w);
}

void Shader::setMatrix2f(GLint var, const Matrix2f m) {
	glUniformMatrix2fv(var, 1, GL_TRUE, m.data());
}

void Shader::setMatrix3f(GLint var, const Matrix3f m) {
	glUniformMatrix3fv(var, 1, GL_TRUE, m.data());
}

void Shader::setMatrix4f(GLint var, const Matrix4f m) {
	glUniformMatrix4fv(var, 1, GL_FALSE, m.data());
}

void Shader::setMatrix2f(GLint var, const GLfloat dat[]) {
	glUniformMatrix2fv(var, 1, GL_TRUE, dat);
}